﻿using System;
using System.Collections.Generic;
using System.Linq;
using Xoohoo.Models;
using Xoohoo.Modules.CMS.Models;
using Xoohoo.Modules.CMS.Repositories;
using Xoohoo.Extensions;
using Xoohoo.Infrastructure;

namespace Xoohoo.Modules.CMS.Services
{
    public class CategoryService : ICategoryService
    {
        private readonly XoohooContext _context;
        private readonly ICategoryRepository _repository;
        private readonly ICacheModule _cache;
        private readonly IModuleRegistry _moduleRegistry;
        private readonly string _categoryListCacheKey = "CategoryList";

        #region ICategoryService 成员

        public CategoryService(XoohooContext context, ICategoryRepository repository, IModuleRegistry moduleRegistry)
        {
            this._context = context;
            this._repository = repository;
            this._moduleRegistry = moduleRegistry;
            this._cache = moduleRegistry.GetModules<ICacheModule>().Last();
        }
        public Category GetItem(Guid categoryID)
        {
            return _repository.GetItem(categoryID);
        }
        public Category GetItem(string categoryName)
        {
            return _repository.GetItem(categoryName);
        }
        public List<Category> GetList(Guid? parentID = null)
        {
            List<Category> list = GetListFromCache();
            if (!list.IsNullOrEmpty())
                return CloneUserGroups(list);
            else
                return _repository.GetList(parentID);
        }
        public ModelResult Save(CategoryInput categoryInput)
        {
            _repository.Save(categoryInput);

            _cache.Invalidate(_categoryListCacheKey);

            return new ModelResult();
        }
        public bool Remove(Guid categoryID)
        {
            bool result = _repository.Remove(categoryID);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        public bool Move(Guid categoryID, MovingTarget target)
        {
            bool result = _repository.Move(categoryID, target);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        public bool Audit(Guid categoryID, bool isAuditing)
        {
            bool result = _repository.Audit(categoryID, isAuditing);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        public bool Recommend(Guid categoryID, bool isCommend)
        {
            bool result = _repository.Recommend(categoryID, isCommend);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        public bool Comment(Guid categoryID, bool allowComment)
        {
            bool result = _repository.Comment(categoryID, allowComment);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        public bool Audit(IEnumerable<Guid> iDs, bool isAuditing)
        {
            bool result = _repository.Audit(iDs, isAuditing);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        public bool Recommend(IEnumerable<Guid> iDs, bool isCommend)
        {
            bool result = _repository.Recommend(iDs, isCommend);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        public bool Comment(IEnumerable<Guid> iDs, bool allowComment)
        {
            bool result = _repository.Comment(iDs, allowComment);
            _cache.Invalidate(_categoryListCacheKey);
            return result;
        }
        #endregion

        #region Private Methods

        private List<Category> CloneUserGroups(IEnumerable<Category> source)
        {
            if (source.IsNullOrEmpty())
                return new List<Category>();

            //深度克隆
            return (source.DeepClone() as IEnumerable<Category>).ToList();

        }

        /// <summary>
        /// 创建父节点路径
        /// </summary>
        /// <param name="source"></param>
        /// <param name="target"></param>
        /// <param name="parentID"></param>
        private void CreateParentPath(IEnumerable<Category> source, IList<Category> target, Guid? parentID)
        {
            if (parentID.IsNullOrEmpty() || source == null || target == null) return;

            Category parent = source.FirstOrDefault(m => m.CategoryID == parentID);
            if (parent != null && target.All(m => m.CategoryID != parent.CategoryID)/*避免死循环*/)
            {
                target.Insert(0, parent);
                CreateParentPath(source, target, parent.ParentID);
            }
        }

        private List<Category> GetListFromCache(Guid? parentID = null)
        {
            if (_cache != null)
                return _cache.GetItem<List<Category>>(
                    _categoryListCacheKey, () => _repository.GetList(),
                    null
                    );
            else
                return null;
        }

        #endregion
    }
}
